﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using log4net;
using System.Reflection;

namespace Cn.Edwon.Web.Crud {
    public class ContextHelper {
        public static ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
        public static ModelEO Parse(Uri uri) {
            return Parse(ClientHelper.IdentyUri(uri));
        }
        public static ModelEO Parse(String modelName) {
            ModelEO model = new ModelEO();
            if (ClientHelper.CrudEnable) { 
                //在web.config中定义了crud的配置
                //读取crud配置，补充model的属性值
                XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable());
                xnm.AddNamespace("ns", "urn:edwon-cn:configuration");
                XmlDocument doc = new XmlDocument();
                try {
                    doc.Load(ClientHelper.CrudConfigUri);
                } catch (Exception ex) {
                    log.Error("加载crud配置文件(Uri:" + ClientHelper.CrudConfigUri + ")时错误", ex);
                    throw new Exception("CRUD配置文件解析错误");
                }
                String pattern = "/ns:jedwon/ns:crud/ns:models/ns:model[@name='" + modelName + "']";
                XmlNode modelNode = doc.SelectSingleNode(pattern,xnm);
                if (modelNode == null) {
                    log.Debug("没找到model[@name='" + modelName + "']节点");
                    return null;
                }
                if (modelNode.Attributes["type"] == null) {
                    log.Error("model缺少type属性定义");
                    throw new Exception("model缺少type属性定义");
                }
                Type modelT;
                try {
                    String[] fullName = modelNode.Attributes["type"].Value.Replace(" ", "").Split(',');
                    Assembly assem = Assembly.Load(fullName[1]);
                    modelT = assem.GetType(fullName[0]);
                } catch(Exception ex) {
                    log.Error("无法解析mode的type[" + modelNode.Attributes["type"].Value + "]定义",ex);
                    throw ex;
                }
                try {
                    model = HbmReader.Parse(modelT);
                } catch (Exception ex) {
                    log.Error("解析model的hbm配置文件错误",ex);
                    throw ex;
                }
                model.Type = modelT;
                model.HasCreate = ReadBooleanAttr(modelNode, "create",true);
                model.HasDelete = ReadBooleanAttr(modelNode, "delete", true);
                model.HasRead = ReadBooleanAttr(modelNode, "read", true);
                model.HasUpdate = ReadBooleanAttr(modelNode, "update", true);
                model.HasOrder = ReadBooleanAttr(modelNode, "order", false);
                model.PageSize = 30;
                if(modelNode.Attributes["pagesize"]!=null){
                    try {
                        model.PageSize = Convert.ToInt32(modelNode.Attributes["pagesize"].Value);
                    } catch {}
                }
                //遍历Property节点
                XmlNodeList pnodes = modelNode.SelectNodes("ns:property", xnm);
                IList<PropertyEO> newPros = new List<PropertyEO>();

                foreach (XmlNode pnode in pnodes) {
                    if (pnode.Attributes["name"] == null) continue;
                    String name = pnode.Attributes["name"].Value;
                    PropertyEO eo = FindPropertyEO(model.Properties, name);
                    if (eo == null) {
                        eo = new PropertyEO();
                        eo.Name = name;
                        eo.Type = typeof(String);
                        eo.NotNull = false;
                        eo.Length = 0;
                        eo.Unique = false;
                    }
                    if (pnode.Attributes["data-type"] != null) {
                        eo.DataType = pnode.Attributes["data-type"].Value;
                    } else {
                        eo.DataType = "text";
                    }
                    if (pnode.Attributes["data-src"] != null) {
                        eo.DataSrc = pnode.Attributes["data-src"].Value;
                    } else {
                        eo.DataSrc = "";
                    }
                    if (pnode.Attributes["order"] != null) {
                        eo.Order = pnode.Attributes["order"].Value;
                    } else {
                        eo.Order = "";
                    }
                    if (pnode.Attributes["datasource"] != null) {
                        String dsname = pnode.Attributes["datasource"].Value;
                        eo.DataSource = ParseDsNode(ref doc,dsname);
                    }
                    eo.InForm = ReadBooleanAttr(pnode, "in-form", true);
                    eo.InList = ReadBooleanAttr(pnode, "in-list",true);
                    eo.InSearch = ReadBooleanAttr(pnode, "in-search", false);
                    eo.Editable = ReadBooleanAttr(pnode, "editable", true);
                    if(pnode.Attributes["not-null"]!=null)
                        eo.NotNull = ReadBooleanAttr(pnode, "not-null", true);
                    eo.Label = pnode.InnerText;
                    newPros.Add(eo);
                }
                model.Properties = newPros;
            }
            return model;
        }
        private static DataSourceEO ParseDsNode(ref XmlDocument doc,String dsname) {
            XmlNamespaceManager xnm = new XmlNamespaceManager(new NameTable());
            xnm.AddNamespace("ns", "urn:edwon-cn:configuration");
            XmlNode ds = doc.SelectSingleNode("//ns:crud/ns:datasource/ns:resource[@name='" + dsname + "']", xnm);
            if (ds == null) return null;
            DataSourceEO dseo = new DataSourceEO();
            if (ds.Attributes["type"] != null) {
                String[] t = ds.Attributes["type"].Value.Replace(" ", "").Split(',');
                dseo.DataType = Assembly.Load(t[1]).GetType(t[0]);
            }
            if (ds.Attributes["text-field"] != null)
                dseo.TxtColumn = ds.Attributes["text-field"].Value;

            if (ds.Attributes["value-field"] != null)
                dseo.ValColumn = ds.Attributes["value-field"].Value;

            return dseo;
        }
        private static PropertyEO FindPropertyEO(IList<PropertyEO> properties, String name) {
            foreach (PropertyEO p in properties) {
                if (p.Name == name) return p;
            }
            return null;
        }
        private static Boolean ReadBooleanAttr(XmlNode node, String Attr, Boolean def) {
            if (node.Attributes[Attr]==null || String.IsNullOrEmpty(node.Attributes[Attr].Value)) {
                return def;
            } else {
                return (node.Attributes[Attr].Value == "yes"
                            || node.Attributes[Attr].Value == "true"
                            || node.Attributes[Attr].Value == "1");
            }
        }
    }
}
